from nmap import PortScanner
from socket import gethostbyname, gaierror


def check_port(target_host: str, scan_ports=None, scan_arguments='-sV'):
    """
    :param target_host: 主机地址
    :param scan_ports: 扫描的端口，可以指定范围
    :param scan_arguments: 扫描参数
    :return:
    """

    scan_result = {}  # 创建一个字典保存扫描结果，格式"ip:扫描信息"

    try:
        target_host = gethostbyname(target_host)  # 如果输入的是域名，则转换为IP地址
    except gaierror:
        scan_result['ip或域名输入错误:'] = 'Example: 192.168.1.10 or 192.168.1.10,192.168.1.20\
         or 192.168.1.0/24 or www.test.com'
        return scan_result
    except Exception as error:
        print(f"未知错误：{error}")
        return scan_result

    nm = PortScanner()  # 创建一个扫描对象
    hosts = target_host.split(",")

    for host in hosts:
        try:
            scan_args = f"{scan_arguments} {scan_ports}" if scan_ports else scan_arguments
            nm.scan(hosts=host, ports=scan_ports, arguments=scan_args)  # 扫描

            for ip in nm.all_hosts():  # 提取扫描结果
                one_result = []  # 保存当前IP对应的主机的扫描结果
                if 'osmatch' in nm[ip] and nm[ip]['osmatch']:
                    one_result.append(f"操作系统为: {nm[ip]['osmatch'][0]['name']}")  # 操作系统
                if scan_ports:  # 如果扫描端口提取端口信息
                    for port in nm[ip].all_tcp():
                        if nm[ip]['tcp'][port]['state'] == 'open':
                            port_info = f"端口: {port} 名称: {nm[ip]['tcp'][port]['name']} 状态: {nm[ip]['tcp'][port]['state']} "
                            port_info += f"版本: {nm[ip]['tcp'][port].get('version', '')} 服务: {nm[ip]['tcp'][port].get('product', '')}"
                            one_result.append(port_info)
                scan_result[ip] = one_result
        except gaierror:
            scan_result['ip或域名输入错误:'] = 'Example: 192.168.1.10 or 192.168.1.10,192.168.1.20\
             or 192.168.1.0/24 or www.test.com'
            break
        except Exception as error:
            print(f"未知错误：{error}")
            break

    return scan_result
